#-*- coding: utf-8 -*-

import xbmc, xbmcaddon
import os, re, select, socket

# Script constants
__addon__       = xbmcaddon.Addon (id='script.service.android-notifier')
__addonname__  = __addon__.getAddonInfo('name')
__addonid__    = __addon__.getAddonInfo('id')
__cwd__        = __addon__.getAddonInfo('path').decode("utf-8")
__version__    = __addon__.getAddonInfo('version')
__language__   = __addon__.getLocalizedString
__resource__   = xbmc.translatePath( os.path.join( __cwd__, 'resources', 'lib' ).encode("utf-8") ).decode("utf-8")

class AndroidNotifier ():

    duration = int (__addon__.getSetting ('DURATION')) * 1000

    def error (*args, **kwargs):
        xbmc.log("ERROR: %s %s" % (args, kwargs))

	# Language strings out of ASCII table will trigger errors when sent as notification.
	# smart_unicode handles the UTF-8 conversion for notifications.
    # http://wiki.xbmc.org/index.php?title=Add-on_unicode_paths#smart_unicode_and_smart_utf8
    def smart_unicode (self, s):
        """credit : sfaxman"""
        if not s:
            return ''
        try:
            if not isinstance(s, basestring):
                if hasattr(s, '__unicode__'):
                    s = unicode(s)
                else:
                    s = unicode(str(s), 'UTF-8')
            elif not isinstance(s, unicode):
                s = unicode(s, 'UTF-8')
        except:
            if not isinstance(s, basestring):
                if hasattr(s, '__unicode__'):
                    s = unicode(s)
                else:
                    s = unicode(str(s), 'ISO-8859-1')
            elif not isinstance(s, unicode):
                s = unicode(s, 'ISO-8859-1')
        return s
    
    def smart_utf8 (self, s):
        return self.smart_unicode(s).encode('utf-8')

	# Return the image with addon path
    def get_image (self, img):
        return xbmc.translatePath (os.path.join (xbmcaddon.Addon ().getAddonInfo ('path'), 'media', img))

	# Process notification message
    def notify (self, msg):
		
        notif = False
		
        if msg['evttype'] == 'RING' and __addon__.getSetting ('SHOW_RING') == 'true':
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32001)), msg['evtcont'], self.duration, self.get_image("ring.png"))
            if xbmc.Player().isPlaying() and not xbmc.getCondVisibility('Player.Paused') and __addon__.getSetting ('PAUSE_RING') == 'true':
                xbmc.Player().pause()
                
        elif msg['evttype'] == 'SMS' and __addon__.getSetting ('SHOW_SMS') == 'true':
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32002)), msg['evtcont'], self.duration, self.get_image("sms.png"))

        elif msg['evttype'] == 'MMS' and __addon__.getSetting ('SHOW_MMS') == 'true':
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32003)), msg['evtcont'], self.duration, self.get_image("mms.png"))

        elif msg['evttype'] == 'BATTERY' and __addon__.getSetting ('SHOW_BATTERY') == 'true':
            image = False
            i = 100
            while image == False and i > 0:
                if int (msg['data']) >= i:
                    image = self.get_image ("battery%d.png" % i)
                i = i - 5;
            if image == False:
              image = self.getImage ("battery_unknown.png")
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32004)), msg['evtcont'], self.duration, image)

        elif msg['evttype'] == 'VOICEMAIL' and __addon__.getSetting ('SHOW_VOICEMAIL') == 'true':
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32005)), msg['evtcont'], self.duration, self.get_image("voicemail.png"))

        elif msg['evttype'] == 'PING' and __addon__.getSetting ('SHOW_PING') == 'true':
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32006)), msg['evtcont'], self.duration, self.get_image("app-icon.png"))

        elif msg['evttype'] == 'USER' and __addon__.getSetting ('SHOW_USER') == 'true':
            notif = '"%s", "%s", "%d", "%s"' % (self.smart_utf8(__language__(32007)), msg['evtcont'], self.duration, self.get_image("app-icon.png"))
            
        if notif == False:
			return

        xbmc.log ('Android Notifier - notification [%s]' % notif)
        return xbmc.executebuiltin ("Notification(%s)" % notif)

    # process raw incoming message
    def msg_process (self, rcv):

        if re.search ('/', rcv) == None:
            xbmc.log ('Android Notifier - invalid message [%s]' % rcv)
            return False
            
        msg = {}
        if re.match ('^v2', rcv):
            spl = rcv.split ('/', 5)
            msg['deviceid'] = spl[1]
            msg['notifid']  = spl[2]
            msg['evttype']  = spl[3]
            msg['data']     = spl[4]
            msg['evtcont']  = spl[5]
        else:
            spl = rcv.split ('/', 4)
            msg['deviceid'] = spl[0]
            msg['notifid']  = spl[1]
            msg['evttype']  = spl[2]
            msg['data']     = ''
            msg['evtcont']  = spl[3]
            
        return msg
 
	# Start listening and receive
    def start (self):

        try:
            sudp = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
            sudp.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)	# unlocking the port to let other applications to listen to it as well
            sudp.bind (('0.0.0.0', 10600))
            sudp.setblocking (0)
        except socket.error as msg:
            xbmc.log ('Android Notifier - cannot listen to 0.0.0.0:10600/UDP (%s)' % msg)
            sudp = False
        else:
            xbmc.log ('Android Notifier - start listening on 0.0.0.0:10600/UDP')
            sudp.settimeout(1)

        try:
            stcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            stcp.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)	# try to unlock the port, but won't work in many cases with other application
            stcp.bind (('0.0.0.0', 10600))
            stcp.listen (1)
        except socket.error as msg:
            xbmc.log ('Android Notifier - cannot listen to 0.0.0.0:10600/TCP (%s)' % msg)
            stcp = False
        else:
            xbmc.log ('Android Notifier - start listening on 0.0.0.0:10600/TCP')
            stcp.settimeout(1)

        while not xbmc.abortRequested:

            if not sudp == False:
                ready = select.select ([sudp], [], [], 0.1)
                if ready[0]:
                    rcv = re.sub ('\\x00', '', sudp.recv (1024))
                    xbmc.log ('Android Notifier - receiving (UDP) [%s]' % rcv)
                    msg = self.msg_process (rcv)
                    if not msg == False:
                        self.notify (msg)

            if not stcp == False:
                ready = select.select ([stcp], [], [], 0.1)
                if ready[0]:
                    rcv = re.sub ('\\x00', '', stcp.recv (1024))
                    xbmc.log ('Android Notifier - receiving (TCP) [%s]' % rcv)
                    msg = self.msg_process (rcv)
                    if not msg == False:
                        self.notify (msg)

        if not sudp == False:
            sudp.close ()
            xbmc.log ('Android Notifier - stopped listening on 0.0.0.0:10600/UDP')
        if not stcp == False:
            stcp.close ()
            xbmc.log ('Android Notifier - stopped listening on 0.0.0.0:10600/TCP')

if __addon__.getSetting ('S_STARTUPSLEEP'):
  time.sleep (int (__addon__.getSetting ('S_STARTUPSLEEP')))

AndroidNotifier().start()
